# Copyright 2014 Nick Boultbee
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation

import os
from gi.repository import Gtk, GLib

from quodlibet import print_d, app, config
from quodlibet.plugins import PluginConfigMixin
from quodlibet.qltk import Message
from quodlibet.qltk.entry import UndoEntry
from quodlibet.util.library import get_scan_dirs

from .util import GetPlayerDialog
from .server import SqueezeboxServer, SqueezeboxException


class SqueezeboxPluginMixin(PluginConfigMixin):
    """
    All the Squeezebox connection / communication code in one delicious class
    """

    # Maintain a singleton; we only support one SB server live in QL
    server = None
    ql_base_dir = (os.path.realpath(get_scan_dirs()[0])
                   if get_scan_dirs() else "")
    print_d("Using QL library dir of %s" % ql_base_dir)

    # We want all derived classes to share the config section
    CONFIG_SECTION = "squeezebox"

    @classmethod
    def get_sb_path(cls, song):
        """Gets a SB path to `song` by simple substitution"""
        path = song('~filename')
        return path.replace(cls.ql_base_dir, cls.server.get_library_dir())

    @classmethod
    def post_reconnect(cls):
        pass

    @staticmethod
    def _show_dialog(dialog_type, msg):
        dialog = Message(dialog_type, app.window, "Squeezebox", msg)
        dialog.connect('response', lambda dia, resp: dia.destroy())
        dialog.show()

    @staticmethod
    def quick_dialog(msg, dialog_type=Gtk.MessageType.INFO):
        GLib.idle_add(SqueezeboxPluginMixin._show_dialog, dialog_type, msg)

    @classmethod
    def set_player(cls, val):
        cls.server.current_player = val
        cls.config_set("current_player", val)
        print_d("Setting player to #%d (%s)" % (val, cls.server.players[val]))

    @classmethod
    def check_settings(cls, button):
        cls.init_server()
        if cls.server.is_connected:
            ret = 0
            if len(cls.server.players) > 1:
                dialog = GetPlayerDialog(app.window, cls.server.players,
                                         cls.server.current_player)
                ret = dialog.run() or 0
            else:
                cls.quick_dialog("Squeezebox OK. Using the only player (%s)."
                                 % cls.server.players[0])
            cls.set_player(ret)
            # TODO: verify sanity of SB library path

            # Manage the changeover as best we can...
            cls.post_reconnect()

        else:
            cls.quick_dialog(_("Couldn't connect to %s") % (cls.server,),
                             Gtk.MessageType.ERROR)

    @classmethod
    def PluginPreferences(cls, parent):
        def value_changed(entry, key):
            if entry.get_property('sensitive'):
                cls.server.config[key] = entry.get_text()
                config.set("plugins", "squeezebox_" + key, entry.get_text())

        vb = Gtk.VBox(spacing=12)
        if not cls.server:
            cls.init_server()
        cfg = cls.server.config

        # Server settings Frame
        cfg_frame = Gtk.Frame(label=_("<b>Squeezebox Server</b>"))
        cfg_frame.set_shadow_type(Gtk.ShadowType.NONE)
        cfg_frame.get_label_widget().set_use_markup(True)
        cfg_frame_align = Gtk.Alignment.new(0, 0, 1, 1)
        cfg_frame_align.set_padding(6, 6, 12, 12)
        cfg_frame.add(cfg_frame_align)

        # Tabulate all settings for neatness
        table = Gtk.Table(3, 2)
        table.set_col_spacings(6)
        table.set_row_spacings(6)
        rows = []

        ve = UndoEntry()
        ve.set_text(cfg["hostname"])
        ve.connect('changed', value_changed, 'server_hostname')
        rows.append((Gtk.Label(label=_("Hostname:")), ve))

        ve = UndoEntry()
        ve.set_width_chars(5)
        ve.set_text(str(cfg["port"]))
        ve.connect('changed', value_changed, 'server_port')
        rows.append((Gtk.Label(label=_("Port:")), ve))

        ve = UndoEntry()
        ve.set_text(cfg["user"])
        ve.connect('changed', value_changed, 'server_user')
        rows.append((Gtk.Label(label=_("Username:")), ve))

        ve = UndoEntry()
        ve.set_text(str(cfg["password"]))
        ve.connect('changed', value_changed, 'server_password')
        rows.append((Gtk.Label(label=_("Password:")), ve))

        ve = UndoEntry()
        ve.set_text(str(cfg["library_dir"]))
        ve.set_tooltip_text(_("Library directory the server connects to."))
        ve.connect('changed', value_changed, 'server_library_dir')
        rows.append((Gtk.Label(label=_("Library path:")), ve))

        for (row, (label, entry)) in enumerate(rows):
            label.set_alignment(0.0, 0.5)
            table.attach(label, 0, 1, row, row + 1,
                         xoptions=Gtk.AttachOptions.FILL)
            table.attach(entry, 1, 2, row, row + 1)

        # Add verify button
        button = Gtk.Button(_("_Verify settings"), use_underline=True)
        button.set_sensitive(cls.server is not None)
        button.connect('clicked', cls.check_settings)
        table.attach(button, 0, 2, row + 1, row + 2)

        cfg_frame_align.add(table)
        vb.pack_start(cfg_frame, True, True, 0)
        debug = cls.ConfigCheckButton(_("Debug"), "debug")
        vb.pack_start(debug, True, True, 0)
        return vb

    @classmethod
    def init_server(cls):
        """Initialises a server, and connects to check if it's alive"""
        try:
            cur = int(cls.config_get("current_player", 0))
        except ValueError:
            cur = 0
        cls.server = SqueezeboxServer(
            hostname=cls.config_get("server_hostname", "localhost"),
            port=cls.config_get("server_port", 9090),
            user=cls.config_get("server_user", ""),
            password=cls.config_get("server_password", ""),
            library_dir=cls.config_get("server_library_dir", cls.ql_base_dir),
            current_player=cur,
            debug=cls.config_get_bool("debug", False))
        try:
            ver = cls.server.get_version()
            if cls.server.is_connected:
                print_d(
                    "Squeezebox server version: %s. Current player: #%d (%s)."
                    % (ver, cur, cls.server.get_players()[cur]["name"]))
        except (IndexError, KeyError, SqueezeboxException) as e:
            print_d("Couldn't get player info (%s)." % e)
